package com.zh.web.controller.mp;

import cn.hutool.json.JSONUtil;
import com.github.AopLog;
import com.zh.business.service.mp.impl.MiniPayServiceImpl;
import com.zh.business.service.mp.impl.TaxiOrderInfoServiceImpl;
import com.zh.business.service.mp.impl.TaxiTransactionInfoServiceImpl;
import com.zh.business.service.web.common.IDCommonCodeService;
import com.zh.zhbootcommon.common.BasicConstants;
import com.zh.zhbootcommon.common.CommonKey;
import com.zh.zhbootcommon.common.RedisKey;
import com.zh.zhbootcommon.config.annotation.AutoIdempotent;
import com.zh.zhbootcommon.config.annotation.VerifyToken;
import com.zh.zhbootcommon.config.exception.ZhBootException;
import com.zh.zhbootcommon.domain.DResult;
import com.zh.zhbootcommon.entity.common.CommonCode;
import com.zh.zhbootcommon.entity.taxi.DTaxiOrderInfo;
import com.zh.zhbootcommon.entity.taxi.DTaxiTransactionInfo;
import com.zh.business.vo.mp.PayOrderReq;
import com.zh.business.vo.wechat.*;
import com.zh.zhbootcommon.utils.common.RedisUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 描述: 小程序用户支付
 *
 * @author: yanglin
 * @Date: 2021-08-25-13:02
 * @Version: 1.0
 */
@Slf4j
@VerifyToken(type = 1)
@RestController
@AutoIdempotent
@RequestMapping("/mp/pay/v1")
@Api(value = "小程序用户支付")
@AopLog(type = "小程序用户支付",stackTraceOnErr = true)
public class PayController {

    @Autowired
    RedisUtils redisUtils;

    @Autowired
    MiniPayServiceImpl payService;

    @Autowired
    TaxiOrderInfoServiceImpl orderInfoService;

    @Autowired
    TaxiTransactionInfoServiceImpl transactionInfoService;

    @Autowired
    IDCommonCodeService codeService;

    @Transactional
    @ApiOperation(value = "乘客支付下单接口")
    @PostMapping("/payTaxiOrder")
    public DResult payTaxiOrder(HttpServletRequest req, @RequestBody PayOrderReq orderReq) {
        Map<String, String> resultMap = new HashMap<>();
        this.verifyOrder(orderReq);
        // 获取订单信息
        try {
            UnifiedOrderRep rep = payService.placeOrder(req, orderReq);
            if(BasicConstants.SUCCESS.equalsIgnoreCase(rep.getResult_code())
                    && BasicConstants.SUCCESS.equalsIgnoreCase(rep.getReturn_code())) {
                resultMap.put("prepayId", rep.getPrepay_id());
                resultMap.put("orderCode", orderReq.getOrderCode());
                log.info("[{}]发起支付->SUCCESS, prepayId->{}", orderReq.getOrderCode(), rep.getPrepay_id());
                // 支付信息存储
                DTaxiTransactionInfo transactionInfo = DTaxiTransactionInfo.builder()
                        .mOpenid(orderReq.getOpenId()).orderCode(orderReq.getOrderCode())
                        .payPrice(orderReq.getTotalFree()).payStatus(CommonKey.PAY_STATUS_10.getValue())
                        .build();
                transactionInfoService.save(transactionInfo);
                // 支付订单存储到缓存
                String orderPayKey = RedisKey.ORDER_PAY_INFO.getValue() + orderReq.getOrderCode();
                CommonCode commonCode = codeService.getCommonCodeByCode(CommonKey.ORDER_PAY_TIME.getValue());
                long expireTime = 1;
                if (Objects.nonNull(commonCode)) {
                    expireTime = Long.parseLong(commonCode.getCContent());
                }
                redisUtils.set(orderPayKey, JSONUtil.toJsonStr(transactionInfo), expireTime);
                return DResult.of(resultMap);
            }else{
                log.info("[{}]发起支付->FAIL, errCode->{}, errDesc->{}", orderReq.getOrderCode(), rep.getErr_code(), rep.getErr_code_des());
                return DResult.failed(rep.getErr_code(), rep.getErr_code_des());
            }
        } catch (Exception e) {
            log.error("payTaxiOrder-> {}", e.getMessage());
            throw new ZhBootException("发起支付失败!");
        }
    }

    @Transactional
    @ApiOperation(value = "查询支付结果接口")
    @PostMapping("/payQueryOrder")
    public DResult payQueryOrder(@RequestBody PayOrderReq orderReq) {
        this.verifyOrder(orderReq);
        try {
            OrderQueryRep orderRep = payService.queryOrder(orderReq);
            if(BasicConstants.SUCCESS.equals(orderRep.getReturn_code())
                    && BasicConstants.SUCCESS.equals(orderRep.getResult_code())
                    && BasicConstants.SUCCESS.equals(orderRep.getTrade_state())) {
                log.info("查询订单[{}]支付结果->SUCCESS, {}", orderReq.getOrderCode(), CommonKey.getName(orderRep.getTrade_state()).getName());
                // 更新订单状态
                DTaxiOrderInfo orderInfo = orderInfoService.getOrderInfoByCode(orderReq.getOrderCode());
                if (Objects.nonNull(orderInfo)) {
                    orderInfo.setOrderStatus(CommonKey.ORDER_STATUS_60.getValue());
                    orderInfoService.updateById(orderInfo);
                }
                // 更新支付订单-支付状态
                DTaxiTransactionInfo transactionInfo = transactionInfoService.queryTransactionByCode(orderReq.getOrderCode());
                if (Objects.nonNull(transactionInfo)) {
                    transactionInfo.setPayStatus(CommonKey.PAY_STATUS_30.getValue());
                    transactionInfoService.updateById(transactionInfo);
                }
                String orderPayKey = RedisKey.ORDER_PAY_INFO.getValue() + orderReq.getOrderCode();
                if (redisUtils.hasKey(orderPayKey)){
                    long expireTime = redisUtils.getExpire(orderPayKey);
                    redisUtils.set(orderPayKey, JSONUtil.toJsonStr(transactionInfo), expireTime);
                }
                return DResult.success();
            }else{
                log.info("查询订单[{}]支付结果->FAIL, {}", orderReq.getOrderCode(), CommonKey.getName(orderRep.getTrade_state()).getName());
                return DResult.of(orderRep.getTrade_state(), CommonKey.getName(orderRep.getTrade_state()).getName());
            }
        } catch (Exception e) {
            log.error("payQueryOrder-> {}", e.getMessage());
            throw new ZhBootException("查询支付结果失败!");
        }
    }

    @ApiOperation(value = "关闭支付订单接口")
    @PostMapping("/payCloseOrder")
    public DResult payCloseOrder(@RequestBody PayOrderReq orderReq) {
        this.verifyOrder(orderReq);
        try {
            CloseOrderRep orderRep = payService.closeOrder(orderReq);
            if(BasicConstants.SUCCESS.equals(orderRep.getReturn_code())
                    && BasicConstants.SUCCESS.equals(orderRep.getResult_code())) {
                log.info("关闭支付订单[{}]->SUCCESS", orderReq.getOrderCode());
                return DResult.success();
            }else{
                log.info("关闭支付订单[{}]->FAIL, errCode->{}, errDesc->{}", orderReq.getOrderCode(), orderRep.getErr_code(), orderRep.getErr_code_des());
                return DResult.of(orderRep.getErr_code(), orderRep.getErr_code_des());
            }
        } catch (Exception e) {
            log.error("payCloseOrder-> {}", e.getMessage());
            throw new ZhBootException("关闭支付订单失败!");
        }
    }

    @Transactional
    @ApiOperation(value = "申请退款接口")
    @PostMapping("/payApplyForRefund")
    public DResult payApplyForRefund(@RequestBody PayOrderReq orderReq) {
        this.verifyOrder(orderReq);
        try {
            RefundRep refundRep = payService.applyForRefund(orderReq);
            if(BasicConstants.SUCCESS.equals(refundRep.getReturn_code())
                    && BasicConstants.SUCCESS.equals(refundRep.getResult_code())) {
                log.info("申请退款订单[{}]->SUCCESS", orderReq.getOrderCode());
                // 更新支付订单-支付状态
                DTaxiTransactionInfo transactionInfo = transactionInfoService.queryTransactionByCode(orderReq.getOrderCode());
                if (Objects.nonNull(transactionInfo)) {
                    transactionInfo.setPayStatus(CommonKey.PAY_STATUS_60.getValue());
                    transactionInfoService.updateById(transactionInfo);
                }
                String orderPayKey = RedisKey.ORDER_PAY_INFO.getValue() + orderReq.getOrderCode();
                if (redisUtils.hasKey(orderPayKey)){
                    long expireTime = redisUtils.getExpire(orderPayKey);
                    redisUtils.set(orderPayKey, JSONUtil.toJsonStr(transactionInfo), expireTime);
                }
                return DResult.success();
            }else{
                log.info("申请退款订单[{}]->FAIL, errCode->{}, errDesc->{}", orderReq.getOrderCode(), refundRep.getErr_code(), refundRep.getErr_code_des());
                return DResult.of(refundRep.getErr_code(), refundRep.getErr_code_des());
            }
        } catch (Exception e) {
            log.error("payApplyForRefund-> {}", e.getMessage());
            throw new ZhBootException("申请退款失败!");
        }
    }

    @Transactional
    @ApiOperation(value = "查询退款接口")
    @PostMapping("/payQueryRefund")
    public DResult payQueryRefund(@RequestBody PayOrderReq orderReq) {
        this.verifyOrder(orderReq);
        try {
            RefundQueryRep queryRep = payService.queryRefund(orderReq);
            if(BasicConstants.SUCCESS.equals(queryRep.getReturn_code())
                    && BasicConstants.SUCCESS.equals(queryRep.getResult_code())) {
                log.info("查询退款订单[{}]->SUCCESS", orderReq.getOrderCode());
                // 更新支付订单-支付状态
                DTaxiTransactionInfo transactionInfo = transactionInfoService.queryTransactionByCode(orderReq.getOrderCode());
                if (Objects.nonNull(transactionInfo)) {
                    transactionInfo.setPayStatus(CommonKey.PAY_STATUS_70.getValue());
                    transactionInfoService.updateById(transactionInfo);
                }
                // 更新支付状态
                return DResult.success();
            }else{
                log.info("查询退款订单[{}]->FAIL, errCode->{}, errDesc->{}", orderReq.getOrderCode(), queryRep.getErr_code(), queryRep.getErr_code_des());
                return DResult.of(queryRep.getErr_code(), queryRep.getErr_code_des());
            }
        } catch (Exception e) {
            log.error("payQueryRefund-> {}", e.getMessage());
            throw new ZhBootException("查询退款失败!");
        }
    }

    /**
     * 订单数据验证
     * @param orderReq
     */
    public void verifyOrder(PayOrderReq orderReq){
        // 获取订单信息
        if (Objects.isNull(orderReq)) {
            throw new ZhBootException("参数为空!");
        }
        DTaxiOrderInfo orderInfo = orderInfoService.getOrderInfoByCode(orderReq.getOrderCode());
        if (Objects.isNull(orderInfo)) {
            throw new ZhBootException("订单不存在!");
        }
    }
}
